package com.jisf.driver.component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jisf.driver.entity.dto.UserChatDto;
import com.jisf.driver.entity.po.Chat;
import com.jisf.driver.entity.po.User;
import com.jisf.driver.exception.LoginException;
import com.jisf.driver.response.GlobalConstant;
import com.jisf.driver.response.ResultCode;
import com.jisf.driver.service.IChatService;
import com.jisf.driver.service.IUserService;
import com.jisf.driver.service.impl.UserDetailsImpl;

import com.jisf.driver.utils.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Classname WebSocketServer
 * @Description TODO
 * @Date 2022/5/6 3:44
 * @Created by jisf：【429627912@qq.com】
 */
@ServerEndpoint(value = "/chat/{id}")
@Component
public class WebSocketServer {

    private static IUserService iUserService;

    private static RedisUtil redisUtil;

    private static IChatService iChatService;

    @Autowired
    public void setIUserService(IUserService iUserService) {
        WebSocketServer.iUserService = iUserService;
    }

    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        WebSocketServer.redisUtil = redisUtil;
    }

    @Autowired
    public void setIChatService(IChatService iChatService){
        WebSocketServer.iChatService = iChatService;
    }

//    @Autowired
//    public WebSocketServer(IUserService iUserService, RedisUtil redisUtil) {
//        WebSocketServer.iUserService = iUserService;
//        WebSocketServer.redisUtil = redisUtil;
//        System.out.println("WebSocketServer 加载");
//    }

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 记录当前在线连接数
     */
    public static final Map<Integer, Map<String, Object>> sessionMap = new ConcurrentHashMap<>();


    /**
     * 连接建立成功调用的方法
     * @param session
     * @param id
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("id") Integer id) {

        //从redis中获取用户信息
        String redisKey = "userId:" + id;
        UserDetailsImpl userDetails = redisUtil.getCacheObject(redisKey);
        if (Objects.isNull(userDetails)){
            throw new LoginException(ResultCode.USER_NOT_LOGIN);
        }
        User user = userDetails.getUser();
        String name = user.getName();

        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        map.put("name", name);
        map.put("session", session);
        // 在线用户信息存入map集合中
        sessionMap.put(id, map);
        // 获取聊天用户列表
        JSONObject users = getUsers();

//        {"studentUsers": [{"id": "1","name": "张三"}],"coachUsers": [],"managerUsers": [],"onlineUsers": []}
        sendAllMessage(JSONObject.toJSONString(users));  // 后台发送消息给所有的客户端
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("id") Integer id) {
        sessionMap.remove(id);
    }

    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("id") Integer id) {

        //从redis中获取用户信息
        String redisKey = "userId:" + id;
        UserDetailsImpl userDetails = redisUtil.getCacheObject(redisKey);
        if (Objects.isNull(userDetails)){
            throw new LoginException(ResultCode.USER_NOT_LOGIN);
        }
        User user = userDetails.getUser();
        String name = user.getName();

        JSONObject obj = JSONObject.parseObject(message);
        Integer toUserId = Integer.parseInt(obj.getString("to")); // to表示发送给哪个用户，比如 admin
        String text = obj.getString("text"); // 发送的消息文本  hello
        // {"to": 1, "text": "聊天文本"}

        // 服务器端 再把消息组装一下，组装后的消息包含发送人和发送的文本内容
        // {"from": "zhang", "text": "hello"}
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("from", id);  // from 是 1
        jsonObject.put("name", name);
        jsonObject.put("text", text);  // text 同上面的text

        // 聊天消息存入数据库
        Chat chat = new Chat();
        chat.setInitiator(id);
        chat.setReceiver(toUserId);
        chat.setMessage(text);
        chat.setSendTime(new Date());
        ResultCode resultCode = iChatService.sendMessage(chat);
        if (resultCode.getCode().equals(GlobalConstant.SUCCESS)){

            Map<String, Object> map = sessionMap.get(toUserId);
            Session toSession = null;
            if (map != null){
                toSession = (Session)map.get("session"); // 根据 to用户名来获取 session，再通过session发送消息文本
            }
            if (toSession != null) {
                this.sendMessage(jsonObject.toString(), toSession);
            }
        }else {
            this.sendErrorMessage(resultCode.getMessage(), session);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 服务端发送消息给客户端
     */
    private void sendMessage(String message, Session toSession) {
        try {
            log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

    /**
     * 服务端发送消息给所有客户端
     */
    private void sendAllMessage(String message) {
        try {
            Set<Integer> sets = sessionMap.keySet();
            for (Integer set : sets) {
                Session session = (Session)sessionMap.get(set).get("session");
                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

    /**
     * 服务端异常信息给客户端
     */
    private void sendErrorMessage(String message, Session session) {
        try {
            log.info("服务端给客户端[{}]发送异常信息{}", session.getId(), message);
            session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

    /**
     * 获取所有用户
     * @return
     */
    private JSONObject getUsers(){
        JSONObject users = new JSONObject();
        users.put("studentUsers", getAllStudents());
        users.put("coachUsers", getAllCoaches());
        users.put("managerUsers", getAllManagers());
        users.put("onlineUsers", getOnlineUsers());
        return users;
    }

    /**
     * 获取所有在线用户
     * @return
     */
    private JSONArray getOnlineUsers(){
        JSONArray array = new JSONArray();
        List<UserChatDto> userChat = new ArrayList<>();
        for (Integer key : sessionMap.keySet()) {
            UserChatDto user = new UserChatDto();
            Map<String, Object> map = sessionMap.get(key);
            int id = (int)map.get("id");
            String name = (String) map.get("name");
            user.setId(id);
            user.setName(name);
            userChat.add(user);
        }
        return JSONArray.parseArray(JSON.toJSONString(userChat));
    }

    /**
     * 获取所有学员
     * @return
     */
    private JSONArray getAllStudents(){
        List<UserChatDto> userChat = iUserService.getUserChat(5);
        return JSONArray.parseArray(JSON.toJSONString(userChat));
    }

    /**
     * 获取所有教练
     * @return
     */
    private JSONArray getAllCoaches(){
        List<UserChatDto> userChat = iUserService.getUserChat(4);
        return JSONArray.parseArray(JSON.toJSONString(userChat));
    }

    /**
     * 获取所有经理
     * @return
     */
    private JSONArray getAllManagers(){
        List<UserChatDto> userChat = iUserService.getUserChat(2);
        return JSONArray.parseArray(JSON.toJSONString(userChat));

    }
}
